home *** CD-ROM | disk | FTP | other *** search
- # terminalsize.py - find size of terminal
- # Copyright (C) 2008 Canonical, Ltd.
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, version 3 of the License.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- # Inspired by code by Chuck Blake, at
- # http://pdos.csail.mit.edu/~cblake/cls/cls.py, but rewritten in an
- # attempt to clarify things. This code is slightly tricky, so I thought
- # the extra clarity would be worth it.
-
- import fcntl
- import os
- import struct
- import termios
-
-
- def get_terminal_size(fd=1):
- """Return size of terminal attached to the standard output.
-
- Use ioctl(2) to query a terminal for its size, given a file
- descriptor attached to the terminal. Return (None, None) if this
- fails, otherwise a tuple (columns, rows).
-
- (The optional 'fd' argument can be set to whatever file
- descriptor you want to use. This is useful for unit tests.)
-
- """
-
- try:
- # Do the ioctl call. termios.TIOCGWINSZ is the code to query
- # terminal size (see tty_ioctl(4), at least on Linux). We need
- # to give it a string of suitable size to use as the input
- # buffer for ioctl. Ioctl modifies the buffer and returns the
- # modified buffer as its return value.
- #
- # The manual page specifies a struct winsize to be used, which
- # consists of four unsigned shorts. We use struct.calcsize to
- # compute the size of that.
- #
- # Note that Blake's original code assumes only the first two
- # shorts in the struct are used, and that two shorts fit into
- # four bytes, which is probably true for all the relevant
- # platforms, but is cramped enough that it makes me feel icky.
- # Thus, I assume less. This will still break if the contents
- # of the struct change, but since that would change the system
- # call API, that's unlikely.
-
- buflen = struct.calcsize('hhhh')
- buf = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * buflen)
-
- # ioctl returns a binary buffer that represents the struct
- # at the C level. We unpack it with struct.unpack.
-
- tuple = struct.unpack('hhhh', buf)
- except:
- # If anything went wrong, we give up and claim we don't know.
- return None, None
-
- return tuple[0], tuple[1]
-